import chalk from 'chalk';
import readline from 'readline';
import stringWidth from 'string-width';
import process from "process";
import {DateUtil} from "./DateUtil.js";
import ansiRegex from "ansi-regex";
import {StrUtil} from "./StrUtil.js";
import {OPSConstant} from "../constant/OPSConstant.js";

export class BuildConsoleTable {


    constructor(type) {
        this.data = [];
        this.showHeader = false;
        // 状态颜色
        this.TABLE_STATUS = {
            success: chalk.green('●成功'),
            normal: chalk.green('●正常'),
            error: chalk.red('●异常'),
            warn: chalk.yellow('●警告'),
            wait: chalk.blue('●等待'),
            canceled: chalk.white('●取消'),
            un: chalk.white('●无'),
            running: chalk.cyan('●运行')
        };
        this.type = type;
        this.baseHeaderOffset = 3;
        this.headerOffset = this.baseHeaderOffset;
        this.prefixLines = [];

        // 类型颜色
        this.TYPE_COLOR = {
            support: chalk.yellow('依赖'),
            app: chalk.cyan('应用'),
            plugin: chalk.cyan('插件'),
            jz: chalk.magenta('基座')
        };

        // 列宽配置
        this.COL_WIDTHS = {
            num: 3,
            type: 6,
            name: 28,
            buildStatus: 20,
            deployStatus: 20,
            sonarStatus: 35,
            runStatus: 25,
            time: 16,
            desc: 60,
            version: 55,
            ingress: 24
        };
        this.SEPARATOR = '  ';
        this.HEADER_LABELS = {
            num: '#',
            type: '类型',
            name: '服务',
            buildStatus: '构建',
            sonarStatus: '扫描',
            deployStatus: '部署',
            runStatus: '启动',
            time: '更新时间',
            desc: '描述',
            version: '版本号',
            ingress: 'ingress'
        };
    }

    setPrefixLines(lines = []) {
        if (Array.isArray(lines) && lines.length > 0) {
            this.prefixLines = lines.slice();
            this.headerOffset = this.baseHeaderOffset + this.prefixLines.length;
        } else {
            this.prefixLines = [];
            this.headerOffset = this.baseHeaderOffset;
        }
    }

    pad(str, width) {
        const text = (str ?? '').toString();
        // 去掉ANSI序列再计算宽度
        const cleanStr = text.replace(ansiRegex(), '');
        const visibleLength = stringWidth(cleanStr);

        if (visibleLength > width) {
            let truncated = '';
            let len = 0;
            for (const char of cleanStr) {
                const charWidth = stringWidth(char);
                if (len + charWidth > width - 1) break;
                truncated += char;
                len += charWidth;
            }
            return truncated + '…';
        }
        return text + ' '.repeat(width - visibleLength);
    }

    getActiveColumns() {
        const columns = ['num', 'type', 'name', 'buildStatus'];
        if (this.type === '普通发布' || this.type === '发布单') {
            columns.push('sonarStatus', 'deployStatus', 'runStatus');
        }
        columns.push('time', 'desc');
        if (this.type === '依赖发布单') {
            columns.push('version');
        }
        if (this.type === '发布单') {
            columns.push('ingress');
        }
        return columns;
    }

    formatStatus(statusKey, desc) {
        const indicator = this.TABLE_STATUS[statusKey] ?? (statusKey || '');
        if (indicator && desc) {
            return `${indicator} ${desc}`;
        }
        return indicator || (desc ?? '');
    }

    getColumnValue(row, key, index) {
        switch (key) {
            case 'num':
                return String(index + 1);
            case 'type': {
                const typeKey = row.type;
                if (!typeKey) {
                    return '';
                }
                const colored = this.TYPE_COLOR[typeKey];
                if (colored) {
                    return colored;
                }
                const alias = OPSConstant.TYPE_ALIAS_MAP?.[typeKey];
                if (alias) {
                    return alias;
                }
                return typeKey;
            }
            case 'name': {
                const name = row.name ?? '';
                if (row.opsUrl) {
                    return StrUtil.hyperlink(name, row.opsUrl);
                }
                return name;
            }
            case 'buildStatus':
                return this.formatStatus(row.buildStatus, row.buildDesc);
            case 'deployStatus':
                return this.formatStatus(row.deployStatus, row.deployDesc);
            case 'sonarStatus':
                return this.formatStatus(row.sonarStatus, row.sonarDesc);
            case 'runStatus':
                return this.formatStatus(row.runStatus, row.runDesc);
            case 'time':
                return row.time ?? '';
            case 'desc':
                return row.desc ?? '';
            case 'ingress': {
                const status = row.ingressStatus ?? 'un';
                return this.formatStatus(status, row.ingressDesc);
            }
            default:
                return row[key] ?? '';
        }
    }

    printBorder() {
        const columns = this.getActiveColumns();
        const totalWidth = columns.reduce((sum, key) => sum + this.COL_WIDTHS[key], 0)
            + (columns.length - 1) * this.SEPARATOR.length;
        console.log('-'.repeat(totalWidth));
    }

    printHeader() {
        if (this.showHeader) {
            return
        }
        this.showHeader = true;
        if (console?.clear) {
            console.clear();
        }
        if (this.prefixLines.length > 0) {
            for (const line of this.prefixLines) {
                console.log(line);
            }
        }
        this.printBorder();
        const columns = this.getActiveColumns();
        const header = columns
            .map(key => this.pad(this.HEADER_LABELS[key] ?? key, this.COL_WIDTHS[key]))
            .join(this.SEPARATOR);
        console.log(chalk.bold(header));
    }

    buildLine(row, index) {
        const columns = this.getActiveColumns();
        const cells = columns.map(key => this.pad(this.getColumnValue(row, key, index), this.COL_WIDTHS[key]));
        return cells.join(this.SEPARATOR);
    }

    moveCursorToBottom() {
        if (!process.stdout?.isTTY) {
            return;
        }
        const bottomRow = this.headerOffset + this.data.length + 1;
        readline.cursorTo(process.stdout, 0, bottomRow);
        readline.clearLine(process.stdout, 0);
    }

    // 打印一行（新增或更新）
    printRow(row, index) {
        const line = this.buildLine(row, index);
        if (!process.stdout?.isTTY) {
            console.log(line);
            return;
        }
        readline.cursorTo(process.stdout, 0, index + this.headerOffset);
        readline.clearLine(process.stdout, 0);
        process.stdout.write(line + '\n');
        this.moveCursorToBottom();
    }

    // 添加一行
    addRow(rowObj) {
        const index = this.data.length;
        this.data.push(rowObj);
        this.printRow(rowObj, index);
    }


    /**
     * 获取这行数据
     * @param appName
     * @return {*}
     */
    getRow(appName) {
        const index = this.data.findIndex(r => r.name === appName);
        return this.data[index];
    }

    // 更新一行
    updateRow(newRow) {
        const index = this.data.findIndex(r => r.name === newRow.name);
        if (index === -1) {
            console.error(`未找到服务: ${newRow.name}`);
            return;
        }
        this.data[index] = {...this.data[index], ...newRow};
        this.data[index].time = DateUtil.nowTime();
        this.printRow(this.data[index], index);
    }

}
